package city.spring.modules.bed.controller;

import city.spring.modules.bed.entity.*;
import city.spring.modules.bed.service.BedBuildingService;
import city.spring.modules.bed.service.BedFloorService;
import city.spring.modules.bed.service.BedRoomService;
import city.spring.modules.bed.service.BedService;
import city.spring.modules.consumptionItem.entity.ConsumptionItemsEntity;
import city.spring.modules.consumptionItem.entity.ProjectBedRelationEntity;
import city.spring.modules.consumptionItem.service.ConsumptionItemsService;
import city.spring.modules.consumptionItem.service.ProjectBedRelationService;
import city.spring.utils.TreeDataUtils;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

/**
 * Controller：床位管理
 *
 * @author HouKunLin
 * @date 2020/4/26 0026 14:20
 */
@RestController
@RequestMapping("/bedManagement")
public class BedManagementController extends ApiController {
    /**
     * Service：楼栋信息
     */
    private final BedBuildingService buildingService;
    /**
     * Service：楼层信息
     */
    private final BedFloorService floorService;
    /**
     * Service：房间信息
     */
    private final BedRoomService roomService;
    /**
     * Service：床位信息
     */
    private final BedService bedService;

    private final ProjectBedRelationService projectBedRelationService;
    private final ConsumptionItemsService consumptionItemsService;

    public BedManagementController(BedBuildingService buildingService, BedFloorService floorService, BedRoomService roomService, BedService bedService, ProjectBedRelationService projectBedRelationService, ConsumptionItemsService consumptionItemsService) {
        this.buildingService = buildingService;
        this.floorService = floorService;
        this.roomService = roomService;
        this.bedService = bedService;
        this.projectBedRelationService = projectBedRelationService;
        this.consumptionItemsService = consumptionItemsService;
    }

    /**
     * 获取公寓管理的树形结构数据（楼栋、楼层、房间）
     */
    @GetMapping("tree")
    public Object tree() {
        List<BedBuildingEntity> buildingEntities = buildingService.list();
        ListMultimap<String, BedFloorEntity> floorMultimap = getFloorMultimap(true, false);
        for (BedBuildingEntity entity : buildingEntities) {
            List<BedFloorEntity> entities = floorMultimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedFloorEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        }
        return success(buildingEntities);
    }

    /**
     * 获取公寓管理的树形结构数据（楼栋、楼层、房间、床位）
     */
    @GetMapping(value = "tree", params = {"loadBed=true"})
    public Object treeLoadBed() {
        List<BedBuildingEntity> buildingEntities = buildingService.list();
        ListMultimap<String, BedFloorEntity> floorMultimap = getFloorMultimap(true, true);
        buildingEntities.forEach(entity -> {
            List<BedFloorEntity> entities = floorMultimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedFloorEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        });
        return success(buildingEntities);
    }

    /**
     * 根据护理等级获取公寓管理的树形结构数据（楼栋、楼层、房间、床位）
     *
     * @param categoryId 护理等级ID
     */
    @GetMapping(value = "tree", params = {"loadBed=true", "categoryId"})
    @SuppressWarnings("all")
    public Object treeLoadBed(String categoryId) {
        // 获取到这个护理等级下的所有床位收费项目
        List<ConsumptionItemsEntity> consumptionItemsEntities = consumptionItemsService.lambdaQuery()
                .eq(ConsumptionItemsEntity::getCategoryId, categoryId)
                .eq(ConsumptionItemsEntity::getIsRoom, "1").list();
        Set<String> itemIds = consumptionItemsEntities.stream().map(ConsumptionItemsEntity::getId).collect(Collectors.toSet());
        if (itemIds.isEmpty()) {
            return success(Collections.emptyList());
        }
        List<ProjectBedRelationEntity> list = projectBedRelationService.lambdaQuery().in(ProjectBedRelationEntity::getProjectId, itemIds).list();
        List<BedEntity> bedEntities = bedService.listByIds(list, ProjectBedRelationEntity::getBedId);
        List<BedRoomEntity> roomEntities = roomService.listByIds(bedEntities, BedEntity::getBedRoomId);
        List<BedFloorEntity> floorEntities = floorService.listByIds(roomEntities, BedRoomEntity::getBedFloorId);
        List<BedBuildingEntity> buildingEntities = buildingService.listByIds(floorEntities, BedFloorEntity::getBedBuildingId);

        List<BaseStruct> treeList = new ArrayList<>();
        treeList.addAll(bedEntities);
        treeList.addAll(roomEntities);
        treeList.addAll(floorEntities);
        treeList.addAll(buildingEntities);
        ListMultimap<String, BaseStruct> multimap = TreeDataUtils.handlerTreeDatasource(treeList, "", BaseStruct::getId, BaseStruct::getPid, BaseStruct::getChildren, BaseStruct::setChildren);

        return success(multimap.values());
    }

    /**
     * 以 楼栋ID 为键，收集每一个楼栋的楼层列表信息
     *
     * @return 每个楼栋的楼层信息
     */
    private ListMultimap<String, BedFloorEntity> getFloorMultimap(boolean loadRoom, boolean loadBed) {
        // 获取所有楼层列表
        List<BedFloorEntity> floorEntities = floorService.list();
        // 楼层的房间列表信息
        ListMultimap<String, BedRoomEntity> floorRoomMultimap = null;
        // 判断是否需要加载房间信息
        if (loadRoom) {
            floorRoomMultimap = getFloorRoomMultimap(loadBed);
        }

        BiConsumer<ListMultimap<String, BedRoomEntity>, BedFloorEntity> loadChildren = (multimap, entity) -> {
            List<BedRoomEntity> entities = multimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedRoomEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        };

        // 以 楼栋ID 为键，收集每一个楼栋的楼层列表信息
        ListMultimap<String, BedFloorEntity> multimap = ArrayListMultimap.create();
        for (BedFloorEntity entity : floorEntities) {
            if (loadRoom) {
                loadChildren.accept(floorRoomMultimap, entity);
            }
            multimap.put(entity.getBedBuildingId(), entity);
        }

        return multimap;
    }

    /**
     * 以 楼层ID 为键，收集每一个楼层的房间列表信息
     *
     * @return 每个楼层的房间列表信息
     */
    private ListMultimap<String, BedRoomEntity> getFloorRoomMultimap(boolean loadBed) {
        // 获取所有房间列表
        List<BedRoomEntity> roomEntities = roomService.list();
        // 判断是否需要加载床位信息
        ListMultimap<String, BedEntity> bedMultimap = null;
        if (loadBed) {
            bedMultimap = getBedMultimap();
        }

        BiConsumer<ListMultimap<String, BedEntity>, BedRoomEntity> loadChildren = (multimap, entity) -> {
            List<BedEntity> entities = multimap.get(entity.getId());
            // 重新对列表进行排序
            entities.sort(Comparator.comparing(BedEntity::getGmtCreate, Date::compareTo));
            entity.setChildren(entities);
        };

        // 以 楼层ID 为键，收集每一个楼层的房间列表信息
        ListMultimap<String, BedRoomEntity> multimap = ArrayListMultimap.create();

        for (BedRoomEntity entity : roomEntities) {
            if (loadBed) {
                loadChildren.accept(bedMultimap, entity);
            }
            multimap.put(entity.getBedFloorId(), entity);
        }
        return multimap;
    }

    /**
     * 以 房间ID 为键，收集每一个房间的床位列表信息
     *
     * @return 每个房间的床位列表信息
     */
    private ListMultimap<String, BedEntity> getBedMultimap() {
        // 获取所有房间列表
        List<BedEntity> roomEntities = bedService.list();
        // 以 楼层ID 为键，收集每一个楼层的房间列表信息
        ListMultimap<String, BedEntity> multimap = ArrayListMultimap.create();

        roomEntities.forEach(entity -> multimap.put(entity.getBedRoomId(), entity));

        return multimap;
    }
}
